/*
 * test_socketcan.cpp
 *
 *  Created on: 2013-9-5
 *      Author: zhl
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <linux/can.h>
#include <linux/can/raw.h>
#include <linux/can/error.h>
#include <linux/netlink.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <netinet/in.h>
#include <net/if.h>
#include <fcntl.h>
#include <sys/un.h>
#include <sys/time.h>
#include <time.h>
#include <sys/ioctl.h>
#include <arpa/inet.h>

struct can_bittiming {
	__u32 bitrate;		/* Bit-rate in bits/second */
	__u32 sample_point;	/* Sample point in one-tenth of a percent */
	__u32 tq;			/* Time quanta (TQ) in nanoseconds */
	__u32 prop_seg;		/* Propagation segment in TQs */
	__u32 phase_seg1;	/* Phase buffer segment 1 in TQs */
	__u32 phase_seg2;	/* Phase buffer segment 2 in TQs */
	__u32 sjw;			/* Synchronisation jump width in TQs */
	__u32 brp;			/* Bit-rate prescaler */
};

void mdelay(int milliseconds)
{
	struct timeval time;

	time.tv_sec  = milliseconds / 1000;				// unit = second
	time.tv_usec = (milliseconds % 1000)*1000;		// unit = micro-second

	select(0,NULL,NULL,NULL,&time);
}

int set_can_bittiming( int bitrate );

int main( int argc,char* argv[] )
{
	int					i1;
	int					nbytes;
	int					ret;
	int     			baudrate;
	int					s;
    struct sockaddr_can addr;
    struct ifreq 		ifr;
    struct can_frame 	frame;
    char				str[100];

    fd_set 	fdRead;
	struct timeval	    aTime;
	int					flag = 0;


	printf( "SocketCAN Test V1.0\n" );

	// ���������в��������ں�   ������
	if( argc > 1 )
	{
		baudrate = atoi( argv[1] );
	}
	else
	{
		//baudrate = 250000;
		baudrate = 100000;
	}

	printf( "bitrate is %d\n", baudrate );
	/*set_can_bittiming( baudrate );*/
	system( "ifconfig can0 down" );
	sprintf( str, "ip link set can0 type can bitrate %d restart-ms 100", baudrate );
	system( str );
	system( "ifconfig can0 up" );

    s = socket(PF_CAN, SOCK_RAW, CAN_RAW);
	printf( "SOCK_RAW can sockfd:%d\n", s );
	if( s < 0 )
	{
		return -1;
	}

	int loopback = 0; /* 0 = disabled, 1 = enabled (default) */
    setsockopt(s, SOL_CAN_RAW, CAN_RAW_LOOPBACK, &loopback, sizeof(loopback));

    can_err_mask_t err_mask = ( CAN_ERR_TX_TIMEOUT | CAN_ERR_BUSOFF | CAN_ERR_BUSERROR );

    setsockopt(s, SOL_CAN_RAW, CAN_RAW_ERR_FILTER, &err_mask, sizeof(err_mask));

    strcpy(ifr.ifr_name, "can0" );
    ret = ioctl(s, SIOCGIFINDEX, &ifr);
    if( ret < 0 )
    {
		return -1;
    }

    addr.can_family = AF_CAN;
    addr.can_ifindex = ifr.ifr_ifindex;

    bind(s, (struct sockaddr *)&addr, sizeof(addr));

    frame.can_id = 0x02;
    frame.can_dlc = 8;

    memset( frame.data, 0x32, frame.can_dlc );

    for( i1=0; ;)
    {
        //sleep(1);
		FD_ZERO(&fdRead);
		FD_SET(s,&fdRead);

		aTime.tv_sec = 1;
		aTime.tv_usec = 0;

		ret = select( s+1,&fdRead,NULL,NULL,&aTime );

		if (ret < 0 )
		{
			printf("fdRead select return <0 \n");
			break;
		}

		if( ret > 0 )
		{
			//�ж��Ƿ���¼�
			if (FD_ISSET(s,&fdRead))
			{
				flag = 1;
				//data available, so get it!
				//nbytes = read(s, &frame, sizeof(struct can_frame));
				nbytes = recv(s, &frame, sizeof(struct can_frame), 0 );

				if (nbytes < 0)
				{
					perror("can raw socket read");
					break;
				}
				if( nbytes < (int)sizeof(struct can_frame))
				{
					fprintf(stderr, "read: incomplete CAN frame\n");
					break;
				}
				if( frame.can_id & CAN_ERR_FLAG )
				{
					printf( "can error! \n" );
				}

				i1++;
				printf( "rcv  %d:", i1 );
                printf("canid[%08x],dlc[%d]\ndata: ",frame.can_id,frame.can_dlc);
                for(int i2=0;i2<frame.can_dlc;i2++)
				{
					printf("%02x ",frame.data[i2]);
				}
				printf("\n");

		        mdelay( 500 );
		        /* do something with the received CAN frame: send back */
		        //nbytes = write(s, &frame, sizeof(struct can_frame));
		        //printf( "%d sendbytes: %d\n", i1+1, nbytes );
			}
		}
    }

    close( s );

    return 0;
}


int set_can_bittiming( int bitrate )
{
	struct can_bittiming 	bt;
    char				 	str[256];

    memset( &bt, 0, sizeof(bt));
	bt.bitrate = bitrate;
	switch( bt.bitrate )
	{
		case 1000000:
			bt.tq = 84;					// ns
			bt.prop_seg = 1;
			bt.phase_seg1 = 8;
			bt.phase_seg2 = 2;
			bt.sjw = 2;
			break;
		case 800000:
			bt.tq = 84;					//ns
			bt.prop_seg = 4;
			bt.phase_seg1 = 8;
			bt.phase_seg2 = 2;
			bt.sjw = 2;
			break;
		case 500000:
			bt.tq = 125;				//ns
			bt.prop_seg = 5;
			bt.phase_seg1 = 8;
			bt.phase_seg2 = 2;
			bt.sjw = 2;
			break;
		case 250000:
			bt.tq = 250;				//ns
			bt.prop_seg = 5;
			bt.phase_seg1 = 8;
			bt.phase_seg2 = 2;
			bt.sjw = 2;
			break;
		case 125000:
			bt.tq = 500;				//ns
			bt.prop_seg = 5;
			bt.phase_seg1 = 8;
			bt.phase_seg2 = 2;
			bt.sjw = 2;
			break;

		case 100000:
			bt.tq = 625;
			bt.prop_seg = 5;
			bt.phase_seg1 = 8;
			bt.phase_seg2 = 2;
			bt.sjw = 2;
			break;

		case 60000:
			bt.tq = 1041;
			bt.prop_seg = 5;
			bt.phase_seg1 = 8;
			bt.phase_seg2 = 2;
			bt.sjw = 2;
			break;

		case 50000:
			bt.tq = 1250;
			bt.prop_seg = 5;
			bt.phase_seg1 = 8;
			bt.phase_seg2 = 2;
			bt.sjw = 2;
			break;

		case 20000:
			bt.tq = 3125;
			bt.prop_seg = 5;
			bt.phase_seg1 = 8;
			bt.phase_seg2 = 2;
			bt.sjw = 2;
			break;

		case 10000:
			bt.tq = 100000 / 16;
			bt.prop_seg = 5;
			bt.phase_seg1 = 8;
			bt.phase_seg2 = 2;
			bt.sjw = 2;
			break;
	}

	printf( "ip link set can0 type can tq %d prop-seg %d phase-seg1 %d phase-seg2 %d sjw %d restart-ms 100\n",
			bt.tq, bt.prop_seg, bt.phase_seg1, bt.phase_seg2, bt.sjw );
	system( "ifconfig can0 down");
	sprintf( str, "ip link set can0 type can tq %d prop-seg %d phase-seg1 %d phase-seg2 %d sjw %d restart-ms 100",
			bt.tq, bt.prop_seg, bt.phase_seg1, bt.phase_seg2, bt.sjw );
	system( str );
	system( "ifconfig can0 up");

	return bt.bitrate;
}

